import * as THREE from "three";

class ShaderManager {
    static shaderCode = {};
    static THREE = null;
}

export function SetThreeJS ( three ) {
    ShaderManager.THREE = three;
}

export async function loadShaders () {

    async function loadText ( url: string ) {
        url = new URL( url, import.meta.url ).href;
        const res = await fetch( url );
        return await res.text();
    }

    const globalShaders = [ "header.glsl", "common.glsl", "oklab.glsl", "noise.glsl", "sky.glsl" ];

    const globalShadersCode = [];

    for ( let i = 0; i < globalShaders.length; i++ ) {
        globalShadersCode.push( await loadText( `../../shaders/${ globalShaders[ i ] }` ) );
    }

    async function loadShader ( url: string ) {
        url = new URL( url, import.meta.url ).href;

        const res = await fetch( url );
        let shaderCode = '';
        for ( let i = 0; i < globalShadersCode.length; ++i ) {
            shaderCode += globalShadersCode[ i ] + '\n';
        }
        return shaderCode + '\n' + await res.text();
    }

    ShaderManager.shaderCode[ 'PHONG' ] = {
        vsh: await loadShader( '../../shaders/phong-lighting-model-vsh.glsl' ),
        fsh: await loadShader( '../../shaders/phong-lighting-model-fsh.glsl' ),
    };

    ShaderManager.shaderCode[ 'GRASS' ] = {
        vsh: await loadShader( '../../shaders/grass-lighting-model-vsh.glsl' ),
        fsh: await loadShader( '../../shaders/grass-lighting-model-fsh.glsl' ),
    };

    ShaderManager.shaderCode[ 'TERRAIN' ] = {
        vsh: await loadShader( '../../shaders/terrain-lighting-model-vsh.glsl' ),
        fsh: await loadShader( '../../shaders/terrain-lighting-model-fsh.glsl' ),
    };

    ShaderManager.shaderCode[ 'BUGS' ] = {
        vsh: await loadShader( '../../shaders/bugs-lighting-model-vsh.glsl' ),
        fsh: await loadShader( '../../shaders/bugs-lighting-model-fsh.glsl' ),
    };

    ShaderManager.shaderCode[ 'WIND' ] = {
        vsh: await loadShader( '../../shaders/wind-lighting-model-vsh.glsl' ),
        fsh: await loadShader( '../../shaders/wind-lighting-model-fsh.glsl' ),
    };

    ShaderManager.shaderCode[ 'SKY' ] = {
        vsh: await loadShader( '../../shaders/sky-lighting-model-vsh.glsl' ),
        fsh: await loadShader( '../../shaders/sky-lighting-model-fsh.glsl' ),
    };

    ShaderManager.shaderCode[ 'WATER' ] = {
        vsh: await loadShader( '../../shaders/water-lighting-model-vsh.glsl' ),
        fsh: await loadShader( '../../shaders/water-lighting-model-fsh.glsl' ),
    };

    ShaderManager.shaderCode[ 'WATER-TEXTURE' ] = {
        vsh: await loadShader( '../../shaders/water-texture-vsh.glsl' ),
        fsh: await loadShader( '../../shaders/water-texture-fsh.glsl' ),
    };

    console.log( ShaderManager.shaderCode );

}

export class ShaderMaterial extends THREE.ShaderMaterial {

    constructor ( shaderType: string, parameters: THREE.ShaderMaterialParameters ) {
        parameters.vertexShader = ShaderManager.shaderCode[ shaderType ].vsh;
        parameters.fragmentShader = ShaderManager.shaderCode[ shaderType ].fsh;

        super( parameters );
    }
}

export class GamePBRMaterial extends THREE.MeshStandardMaterial {

    private shader;

    constructor ( shaderType: string, parameters: THREE.MeshStandardMaterialParameters ) {

        super( parameters );

        this.shader = null;
    }
}